{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jtree_intro_md"
      },
      "source": [
        "# JunctionTree"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jtree_desc_md"
      },
      "source": [
        "A `JunctionTree` is an intermediate data structure used in GTSAM's multifrontal variable elimination. It is a `ClusterTree` where each node (cluster) corresponds to a clique in the chordal graph formed during elimination.\n",
        "\n",
        "Key differences from related structures:\n",
        "*   **vs. EliminationTree:** Junction tree nodes can represent the elimination of multiple variables simultaneously (a 'frontal' set), whereas elimination tree nodes typically represent single variable eliminations.\n",
        "*   **vs. BayesTree:** A JunctionTree node contains the original factors associated with the variables being eliminated in that clique. A BayesTree node contains the *result* of eliminating those factors (i.e., a conditional density $P(\\text{Frontals} | \\text{Separator})$).\n",
        "\n",
        "Like `EliminationTree`, direct manipulation of `JunctionTree` objects in Python is uncommon. It's primarily an internal structure used by `eliminateMultifrontal` when producing a `BayesTree`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jtree_colab_md"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/JunctionTree.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jtree_pip_code",
        "tags": [
          "remove-cell"
        ]
      },
      "outputs": [],
      "source": [
        "%pip install --quiet gtsam-develop"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "jtree_import_code"
      },
      "outputs": [],
      "source": [
        "import gtsam\n",
        "import numpy as np\n",
        "\n",
        "# JunctionTree is templated, need concrete types\n",
        "from gtsam import GaussianFactorGraph, Ordering, VariableIndex\n",
        "from gtsam import symbol_shorthand\n",
        "\n",
        "X = symbol_shorthand.X\n",
        "L = symbol_shorthand.L"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jtree_create_md"
      },
      "source": [
        "## Creating a JunctionTree\n",
        "\n",
        "A `JunctionTree` is typically constructed from an `EliminationTree` as part of the multifrontal elimination process. The direct constructor might not be exposed in Python, as it's usually created internally."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "jtree_create_code",
        "outputId": "12345678-9abc-def0-1234-56789abcdef0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Resulting BayesTree (structure mirrors JunctionTree):\n",
            ": cliques: 2, variables: 5\n",
            "- p(x1 l2 x2 )\n",
            "  R = [   1.61245 -0.620174 -0.620174 ]\n",
            "      [         0   1.27098  -1.08941 ]\n",
            "      [         0         0  0.654654 ]\n",
            "  d = [ 0 0 0 ]\n",
            "  mean: 3 elements\n",
            "  l2: 0\n",
            "  x1: 0\n",
            "  x2: 0\n",
            "  logNormalizationConstant: -2.46292\n",
            "  No noise model\n",
            "| - p(l1 x0  | x1)\n",
            "  R = [   1.41421 -0.707107 ]\n",
            "      [         0   1.58114 ]\n",
            "  S[x1] = [ -0.707107 ]\n",
            "          [ -0.948683 ]\n",
            "  d = [ 0 0 ]\n",
            "  logNormalizationConstant: -1.03316\n",
            "  No noise model\n"
          ]
        }
      ],
      "source": [
        "# Create a graph (same as BayesTree example)\n",
        "graph = GaussianFactorGraph()\n",
        "model = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
        "graph.add(X(0), -np.eye(1), np.zeros(1), model)\n",
        "graph.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
        "graph.add(X(1), -np.eye(1), X(2), np.eye(1), np.zeros(1), model)\n",
        "graph.add(L(1), -np.eye(1), X(0), np.eye(1), np.zeros(1), model)\n",
        "graph.add(L(1), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
        "graph.add(L(2), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
        "graph.add(L(2), -np.eye(1), X(2), np.eye(1), np.zeros(1), model)\n",
        "\n",
        "ordering = Ordering.ColamdGaussianFactorGraph(graph)\n",
        "\n",
        "# Perform multifrontal elimination, which uses a JunctionTree internally\n",
        "bayes_tree, remaining_graph = graph.eliminatePartialMultifrontal(ordering)\n",
        "\n",
        "# The resulting BayesTree reflects the structure of the intermediate JunctionTree\n",
        "print(\"Resulting BayesTree (structure mirrors JunctionTree):\")\n",
        "bayes_tree.print()\n",
        "\n",
        "# Accessing the JunctionTree directly isn't typical in Python workflows.\n",
        "# Its structure is implicitly captured by the BayesTree cliques."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "gtsam",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.13.1"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
